using System;
using System.Collections.Generic;

namespace CLELCore.Assembly.BlobStreams.BlobTypes
{
	public class BlobType
	{
		public const byte LOCAL_SIG_BLOB_TYPE = 0x7;

		private byte _type;

		public byte Type
		{
			get
			{
				return _type;
			}
		}

		public BlobType(byte type)
		{
			_type = type;
		}
				
		public static BlobType ParseBlobType(byte [] blob,ref int start)
		{
			if(blob == null)
				throw new ArgumentException("Blob array cannot be null");
			int len = blob.Length;
			if(start >= len)
				throw new IndexOutOfRangeException("Index out of bounds in blob array");
			byte type = blob[start];
			if(type == BlobElementType.ELEMENT_TYPE_VOID || type == BlobElementType.ELEMENT_TYPE_BOOLEAN ||
				type == BlobElementType.ELEMENT_TYPE_CHAR || type == BlobElementType.ELEMENT_TYPE_I1 ||
				type == BlobElementType.ELEMENT_TYPE_U1 || type == BlobElementType.ELEMENT_TYPE_I2 ||
				type == BlobElementType.ELEMENT_TYPE_U2 || type == BlobElementType.ELEMENT_TYPE_I4 ||
				type == BlobElementType.ELEMENT_TYPE_U4 || type == BlobElementType.ELEMENT_TYPE_I8 ||
				type == BlobElementType.ELEMENT_TYPE_U8 || type == BlobElementType.ELEMENT_TYPE_R4 ||
				type == BlobElementType.ELEMENT_TYPE_R8 || type == BlobElementType.ELEMENT_TYPE_STRING)
			{
				start++;
				return new BlobBuiltInType(type);
			}
			else if(type == BlobElementType.ELEMENT_TYPE_GENERICINST)
			{
				start++;
				byte generic_type = blob[start];
				start++;
				int compressed_token;
				uint arg_count;
				Token token;
				List<BlobType> generic_types;
				uint i;
				if(generic_type == BlobElementType.ELEMENT_TYPE_CLASS)
				{
					compressed_token = Blob.ParseCompressedBlobValue(blob,ref start);
					token = TokenDecompressor.DecompressTypeDefOrRefToken(compressed_token);
					arg_count = (uint)Blob.ParseCompressedBlobValue(blob,ref start);
					if(arg_count < 1)
						throw new CLELParserException("Genefic argument count: " + arg_count);
					generic_types = new List<BlobType>();
					for(i = 0;i < arg_count;i++)
					{
						generic_types.Add(BlobType.ParseBlobType(blob,ref start));
					}
					return new BlobGenericClassType(type,generic_type,token,arg_count,generic_types);
				}
			}
			return null;
		}
	}
}
